package lv.servidordisqueria.repositorio;

import java.util.List;

import lv.mensajeriadisqueria.idomain.IDomain;
import lv.servidordisqueria.persistencia.HibernateUtil;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Transaction;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Order;

/**
 * Repositorio generico de acceso a Hibernate, en el se manejaran los mensajes de 
 * insercion, borrado, edicion y busquedas de las entidades genricas.
 * @param <Entity> domain que debe complir para poder accionar el repositorio
 */
public class Repositorio<Entity extends IDomain> {
	
	/**
	 * Insertar una entidad
	 * @param entity entidad
	 */
	public void insertar(Entity entity) {
		Transaction transaction = HibernateUtil.getSession().getTransaction();
		try {
			transaction.begin();
			HibernateUtil.getSession().save(entity);
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		}	
	}

	/**
	 * Insertar una entidad
	 * @param entity entidad
	 */
	public void editar(Entity entity) {
		Transaction transaction = HibernateUtil.getSession().getTransaction();
		try {
			transaction.begin();
			HibernateUtil.getSession().update(entity);
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		}
	}
	
	/**
	 * Borra una entidad en forma logica, Habilitado en forma true.
	 * Actua en cascada.
	 * @param entity
	 */
	public void borrar(Entity entity) {
		//TODO hay que hacer el eliminar fisico en cascada.
	}
	
	/**
	 * Borra una entidad en forma fisica, La elimina definitivamente
	 * de la base de datos. Actua en cascada.
	 * @param entity
	 */
	public void borradoFisico(Entity entity) {
		Transaction transaction = HibernateUtil.getSession().getTransaction();
		try {
			transaction.begin();
			HibernateUtil.getSession().delete(entity);
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		}
	}
	
	/**
	 * Busca todas las entidades
	 * @return la lista de entidades completas
	 */
	@SuppressWarnings("unchecked")
	public List<Entity> buscarTodos(Class<?> clazz) {
		Query query = HibernateUtil.getSession().createQuery("from " + clazz.getName().trim());
		return query.list();
	}
	
	/**
	 * busca una entidad por medio de un filtro de columna y valor
	 * @param entity esta es la entidad de que vamos a buscar
	 * @param columna por la cualse filtra
	 * @param valor de la columna filtrada.
	 * @return la lista de entidades encontradas
	 */
	@SuppressWarnings("unchecked")
	public List<Entity> buscar(Class<?> clazz, String columna, Object valor) {
		Criteria criteria = HibernateUtil.getSession().createCriteria(clazz);
		criteria.add(Expression.eq(columna, valor)).addOrder(Order.asc(columna));
		return criteria.list();
	}
	
	/**
	 * Busca por el id de la entidad
	 * @param id
	 * @return la entidad encontrada
	 */
	@SuppressWarnings("unchecked")
	public Entity buscarPorId(Class<?> clazz, Integer id) {
		return (Entity) HibernateUtil.getSession().get(clazz, id);
	}
}